package com.pokermind.repository.dao.impl;

import com.pokermind.model.po.PokerHandAction;
import com.pokermind.repository.dao.PokerHandActionDao;
import com.pokermind.repository.mapper.PokerHandActionRowMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;

import java.sql.PreparedStatement;
import java.sql.Statement;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * PokerHandAction DAO实现类
 * 使用JdbcTemplate实现手牌行动数据访问操作
 * 
 * @author PokerMind Team
 */
@Repository
public class PokerHandActionDaoImpl implements PokerHandActionDao {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    private final PokerHandActionRowMapper rowMapper = new PokerHandActionRowMapper();
    
    @Override
    public PokerHandAction save(PokerHandAction action) {
        String sql = """
            INSERT INTO poker_hand_actions (
                hand_id, seat_number, player_id, user_id, street, action_sequence, global_sequence,
                action_type, amount, stack, pot, think_time_seconds, create_time, update_time
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """;
        
        KeyHolder keyHolder = new GeneratedKeyHolder();
        
        jdbcTemplate.update(connection -> {
            PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
            ps.setLong(1, action.getHandId());
            ps.setInt(2, action.getSeatNumber());
            ps.setString(3, action.getPlayerId());
            ps.setObject(4, action.getUserId());
            ps.setString(5, action.getStreet());
            ps.setInt(6, action.getActionSequence());
            ps.setInt(7, action.getGlobalSequence());
            ps.setString(8, action.getActionType());
            ps.setBigDecimal(9, action.getAmount());
            ps.setBigDecimal(10, action.getStackAfter());
            ps.setBigDecimal(11, action.getPotAfter());
            ps.setObject(12, action.getThinkTimeSeconds());
            ps.setLong(13, action.getCreateTime() != null ? action.getCreateTime() : System.currentTimeMillis());
            ps.setLong(14, action.getUpdateTime() != null ? action.getUpdateTime() : System.currentTimeMillis());
            return ps;
        }, keyHolder);
        
        Number generatedId = keyHolder.getKey();
        if (generatedId != null) {
            action.setId(generatedId.longValue());
        }
        
        return action;
    }
    
    @Override
    public int batchSave(List<PokerHandAction> actions) {
        String sql = """
            INSERT INTO poker_hand_actions (
                hand_id, seat_number, player_id, user_id, street, action_sequence, global_sequence,
                action_type, amount, stack, pot, think_time_seconds, create_time, update_time
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        """;
        
        return jdbcTemplate.batchUpdate(sql, actions, actions.size(), (ps, action) -> {
            ps.setLong(1, action.getHandId());
            ps.setInt(2, action.getSeatNumber());
            ps.setString(3, action.getPlayerId());
            ps.setObject(4, action.getUserId());
            ps.setString(5, action.getStreet());
            ps.setInt(6, action.getActionSequence());
            ps.setInt(7, action.getGlobalSequence());
            ps.setString(8, action.getActionType());
            ps.setBigDecimal(9, action.getAmount());
            ps.setBigDecimal(10, action.getStackAfter());
            ps.setBigDecimal(11, action.getPotAfter());
            ps.setObject(12, action.getThinkTimeSeconds());
            ps.setLong(13, action.getCreateTime() != null ? action.getCreateTime() : System.currentTimeMillis());
            ps.setLong(14, action.getUpdateTime() != null ? action.getUpdateTime() : System.currentTimeMillis());
        }).length;
    }
    
    @Override
    public Optional<PokerHandAction> findById(Long id) {
        String sql = "SELECT * FROM poker_hand_actions WHERE id = ?";
        try {
            PokerHandAction action = jdbcTemplate.queryForObject(sql, rowMapper, id);
            return Optional.ofNullable(action);
        } catch (EmptyResultDataAccessException e) {
            return Optional.empty();
        }
    }
    
    @Override
    public List<PokerHandAction> findAll() {
        String sql = "SELECT * FROM poker_hand_actions ORDER BY global_sequence";
        return jdbcTemplate.query(sql, rowMapper);
    }
    
    @Override
    public int update(PokerHandAction action) {
        String sql = """
            UPDATE poker_hand_actions SET 
                hand_id = ?, seat_number = ?, player_id = ?, user_id = ?, street = ?, action_sequence = ?,
                global_sequence = ?, action_type = ?, amount = ?, stack_after = ?, pot_after = ?,
                think_time_seconds = ?, update_time = ?
            WHERE id = ?
        """;
        
        return jdbcTemplate.update(sql,
                action.getHandId(), action.getSeatNumber(), action.getPlayerId(), action.getUserId(),
                action.getStreet(), action.getActionSequence(), action.getGlobalSequence(),
                action.getActionType(), action.getAmount(), action.getStackAfter(),
                action.getPotAfter(), action.getThinkTimeSeconds(),
                action.getUpdateTime() != null ? action.getUpdateTime() : System.currentTimeMillis(),
                action.getId()
        );
    }
    
    @Override
    public int deleteById(Long id) {
        String sql = "DELETE FROM poker_hand_actions WHERE id = ?";
        return jdbcTemplate.update(sql, id);
    }
    
    @Override
    public int delete(PokerHandAction action) {
        return deleteById(action.getId());
    }
    
    @Override
    public boolean existsById(Long id) {
        String sql = "SELECT COUNT(1) FROM poker_hand_actions WHERE id = ?";
        Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id);
        return count != null && count > 0;
    }
    
    @Override
    public long count() {
        String sql = "SELECT COUNT(*) FROM poker_hand_actions";
        Long count = jdbcTemplate.queryForObject(sql, Long.class);
        return count != null ? count : 0L;
    }
    
    @Override
    public List<PokerHandAction> findByHandId(Long handId) {
        String sql = "SELECT * FROM poker_hand_actions WHERE hand_id = ? ORDER BY global_sequence";
        return jdbcTemplate.query(sql, rowMapper, handId);
    }
    
    @Override
    public List<PokerHandAction> findByHandIdAndStreet(Long handId, String street) {
        String sql = "SELECT * FROM poker_hand_actions WHERE hand_id = ? AND street = ? ORDER BY action_sequence";
        return jdbcTemplate.query(sql, rowMapper, handId, street);
    }
    
    @Override
    public List<PokerHandAction> findByHandIdAndSeatNumber(Long handId, Integer seatNumber) {
        String sql = "SELECT * FROM poker_hand_actions WHERE hand_id = ? AND seat_number = ? ORDER BY global_sequence";
        return jdbcTemplate.query(sql, rowMapper, handId, seatNumber);
    }
    
    @Override
    public PokerHandAction findLastActionByHandId(Long handId) {
        String sql = "SELECT * FROM poker_hand_actions WHERE hand_id = ? ORDER BY global_sequence DESC LIMIT 1";
        try {
            return jdbcTemplate.queryForObject(sql, rowMapper, handId);
        } catch (EmptyResultDataAccessException e) {
            return null;
        }
    }
    
    @Override
    public long countByHandId(Long handId) {
        String sql = "SELECT COUNT(*) FROM poker_hand_actions WHERE hand_id = ?";
        Long count = jdbcTemplate.queryForObject(sql, Long.class, handId);
        return count != null ? count : 0L;
    }
    
    @Override
    public long countByHandIdAndStreet(Long handId, String street) {
        String sql = "SELECT COUNT(*) FROM poker_hand_actions WHERE hand_id = ? AND street = ?";
        Long count = jdbcTemplate.queryForObject(sql, Long.class, handId, street);
        return count != null ? count : 0L;
    }
    
    @Override
    public int deleteByHandId(Long handId) {
        String sql = "DELETE FROM poker_hand_actions WHERE hand_id = ?";
        return jdbcTemplate.update(sql, handId);
    }
}